package com.yueshop.product.web;


import com.yueshop.product.entity.CategoryEntity;
import com.yueshop.product.service.CategoryService;
import com.yueshop.product.vo.Catelog2Vo;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Controller
public class IndexController {

    @Autowired
    private CategoryService categoryService;

    @Autowired
    RedissonClient redissonClient;


    @Autowired
    StringRedisTemplate redisTemplate;

    @GetMapping({"/","index.html"})
    public String indexPage(Model model){
        long l = System.currentTimeMillis();
        //获取所有一级分类
        List<CategoryEntity> categories= categoryService.getLevel1Catagories();
        System.out.println("耗时:"+(System.currentTimeMillis()-l));
        model.addAttribute("categories",categories);
        return  "index";
    }


    @ResponseBody
    @GetMapping("/index/catalog.json")
    public Map<String,List<Catelog2Vo>> getCatelogJson(){
        Map<String,List<Catelog2Vo>> catelogJson =  categoryService.getCatelogJson();
        return catelogJson;
    }


    @ResponseBody
    @GetMapping("/hello")
    public String sayHello(){
        //1.获取同一把所,只要锁的名字一样,就是同一把锁
        RLock lock = redissonClient.getLock("my-lock");
        //2.加索
        //lock.lock();//阻塞式等待
        //设置过期时间为10秒
        lock.lock(10,TimeUnit.SECONDS);//自动解锁过期时间设置一定要大于业务解锁时间
        //执行业务代码
        try {
            System.out.println("加锁成功,执行业务"+Thread.currentThread().getId());
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("解锁成功"+Thread.currentThread().getId());
            lock.unlock();
        }
        return "hello";
    }


    //保证一定能读到最新数据,修改期间,写锁是一个排他锁(互斥锁),读锁是一个共享锁
    //写锁没释放 读锁必须等待
    //写+读  等待写锁释放
    //读+读  直接读
    //写+写   阻塞方式 (下一个写 必须等待上一个写锁释放)
    //读+ 写  读执行完毕 写才可执行
    // 写 +读 读 读读

    @ResponseBody
    @GetMapping("/write")
    public String write() {
        String s ="";

        //获取读写锁对象, 读和写都是同一个keyrw-lock
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("rw-lock");
        RLock rLock = readWriteLock.writeLock();
        //加写锁
        rLock.lock();
        try {
            System.out.println("写锁加锁成功"+Thread.currentThread().getId());
            s=UUID.randomUUID().toString();
            Thread.sleep(30000);
            redisTemplate.opsForValue().set("writeValue",s);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            rLock.unlock();//解锁
        }
        return s;
    }

    @ResponseBody
    @GetMapping("/read")
    public String read() {
        String s ="";
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("rw-lock");
        //获取读锁
        RLock rLock = readWriteLock.readLock();
        //加索
        rLock.lock();
        try {
            System.out.println("读锁加锁成功"+Thread.currentThread().getId());
            Thread.sleep(30000);
            s= redisTemplate.opsForValue().get("writeValue");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            rLock.unlock();//解锁
        }
        return s;
    }


    //模拟场景  车库停车
    @ResponseBody
    @GetMapping("/park")
    public String park() throws InterruptedException {
        //获取信号量
        RSemaphore park = redissonClient.getSemaphore("park");
        //占用一个车位
       // park.acquire();//阻塞时等待

        boolean b = park.tryAcquire();//返回ture 或false
        if(b){
           //执行业务代码
        }else{
            return "error 当前流量过大请等待";
        }

        return  "ok";//返回ok 就代表 停车成功
    }


    @ResponseBody
    @GetMapping("/go")
    public String go() throws InterruptedException {
        //获取信号量
        RSemaphore park = redissonClient.getSemaphore("park");
        //占用一个车位
        park.release();
        return  "ok";//返回ok 就代表 释放成功
    }




    //模拟场景 放假锁门 5个班级 所有班级走后 才去锁门

    @ResponseBody
    @GetMapping("/lockdoor")
    public String lockdoor() throws InterruptedException {
        //获取闭锁
        RCountDownLatch door = redissonClient.getCountDownLatch("door");
        door.trySetCount(5);//等待5各班级
        door.await();//等待闭锁完成
        return "放假锁门了.....";
    }

    @ResponseBody
    @GetMapping("/goHome/{id}")
    public String goHome(@PathVariable("id") Long id) {
        //获取闭锁
        RCountDownLatch door = redissonClient.getCountDownLatch("door");
        door.countDown();//每执行一次,计数减1
        return  id+"班都走了....";
    }









}
